import datetime
import time

from database import db
from extensions import redis_store
from ..models.fund_channel import FundChannelConfig
from ..models.gateway import GatewayApi
from ..models.order import TradeOrder, GatewayOrder, GatewayOrderResult
from ..signals import  trade

class TradeService(object):
    @classmethod
    def _create_result_return_url_key(cls, result_id):
        return '_RETURN_URL-{}'.format(result_id)

    @classmethod
    def get_payment_result_return_url(cls, result_id):
        return redis_store.get(cls._create_result_return_url_key(result_id)).decode()

    @classmethod
    def store_payment_result_return_url(cls, result_id, return_url):
        from datetime import timedelta
        redis_store.setex(cls._create_result_return_url_key(result_id), timedelta(minutes=60), return_url)

    @classmethod
    def get_gateway_order_result(cls, result_id):
        return GatewayOrderResult.query.filter(GatewayOrderResult.id == result_id).first()

    @classmethod
    def _create_gateway_result_order_no(cls, opts={}):
        if not opts:
            import time
            return str(time.time()).replace('.', '')

    @classmethod
    def verify_order_result(cls, gateway_order_result, verify_data):
        gateway_order = gateway_order_result.gateway_order
        fund_channel = gateway_order_result.fund_channel

        fund_channel_config = cls._get_fund_channel_config(fund_channel)

        gateway_api = GatewayApi.query.filter(GatewayApi.gateway_id == gateway_order.gateway_id).filter(
            GatewayApi.type == 'verify').first()
        if not gateway_api:
            raise
            pass
        verify_api = cls._create_payment_api(gateway_api, 'verify')

        response = verify_api(verify_data, config=fund_channel_config)

        success = response.pop('success', None)
        if success:
            gateway_order_result.status = GatewayOrderResult.STATUS_SUCCESS if success else GatewayOrderResult.STATUS_FAILED
            gateway_order_result.result_code = response.get('result_code', None)
            gateway_order_result.result_message = response.get('result_message', None)

            extension = response.get('extension', None)
            if extension:
                import json
                gateway_order_result.extension = json.dumps(extension)
            import datetime
            now = datetime.datetime.now()
            gateway_order_result.payment_time = now
            gateway_order_result.updated_at = now

            ######################gatewarorder
            gateway_order = gateway_order_result.gateway_order
            gateway_order.updated_at = now
            gateway_order.status = GatewayOrder.STATUS_SUCCESS if success else GatewayOrder.STATUS_FAILED

            for trade_order in gateway_order.trade_orders:
                trade_order.status = TradeOrder.STATUS_SUCCESS if success else TradeOrder.STATUS_FAILED
                ####################
                # TODO 通知支付流水的状态改变了
                trade.on_trade_finished(trade)

        else:
            # 未返回success 则只将结果流水置为 UNKNOW 其他还是在处理中
            gateway_order_result.status = GatewayOrderResult.STATUS_UNKNOWN
        db.session.commit()

    @classmethod
    def _get_fund_channel_config(cls, fund_channel):
        # 查询资金源的配置
        fund_channel_config = FundChannelConfig.query.filter(FundChannelConfig.fund_channel_id == fund_channel.id).all()

        channel_config = {}

        for config in fund_channel_config:
            # channel_config[config.name] = config.name
            value_mode = config.value_mode
            if not value_mode or value_mode == 'string':
                value_separator = config.value_separator
                if value_separator:
                    channel_config[config.name] = config.value.split(value_separator)
                channel_config[config.name] = config.value
            else:
                channel_config[config.name] = config.value
        return channel_config

    @classmethod
    def _make_links(cls, gateway_result_order, *args, **kwargs):

        def join_url(url, *paths):
            import re
            for path in paths:
                url = re.sub(r'/?$', re.sub(r'^/?', '/', path), url)
            return url

        from flask import url_for, request
        links = {}
        for m in ('notify', 'verify'):
            links[m] = join_url(request.url_root,
                                url_for('GatewayCallbackView:{}'.format(m), result_id=gateway_result_order.id)
                                )
        return links

    @classmethod
    def _generate_gateway_order_no(cls, fund_channel):

        # logger.debug('create gateway trade code , order_mode : %s', fund_channel.order_mode)
        if fund_channel.order_mode:
            order_code = []
            for mode in fund_channel.order_mode.split('|'):
                if mode.find(':') > 0:
                    mode, value = mode.split(':')
                    mode = mode.upper()
                    if mode == 'S':
                        order_code.append(value)
                    elif mode == 'D':
                        import datetime
                        order_code.append(datetime.datetime.now().strftime(value))
                    elif mode == 'R' or mode == 'A':
                        import random
                        for i in range(0, int(value)):
                            order_code.append(str(random.randrange(0, 9)))
            return ''.join(order_code)
        else:
            import datetime
            # from extensions import next_id
            return '{}{}'.format(datetime.datetime.now().strftime('%Y%m%d%H%M%S'))

    @classmethod
    def merge_payment(cls, payment_orders, payment_type, fund_channel, currency, *args, **kwargs):
        now = datetime.datetime.now()
        from decimal import Decimal
        amount = Decimal.from_float(0.00)
        gateway_order = GatewayOrder(
            currency=currency,
            status=GatewayOrder.STATUS_WAITING_FOR_SEND,
            gateway_id=fund_channel.gateway.id,
            created_at=now,
            updated_at=now
        )
        for order in payment_orders:
            amount += order.amount
            order.gateway_order = gateway_order
            # db.session.save(order)
        gateway_order.amount = amount

        db.session.add(gateway_order)
        db.session.commit()
        if True:
            # TODO, 未来可以根据网关的属性，是单笔还是批次发送,现在全是单笔
            gateway_order.next_submit_time = now
            gateway_order_result = GatewayOrderResult(
                order_no=cls._create_gateway_result_order_no(),
                result_code='',
                result_message='',
                fund_channel_id=fund_channel.id,
                gateway_order_id=gateway_order.id,
            )
            db.session.add(gateway_order_result)
            db.session.commit()
        # 开始实际支付流程
        gateway = fund_channel.gateway

        gateway_api = GatewayApi.query.filter(GatewayApi.gateway_id == gateway.id).filter(
            GatewayApi.type == payment_type).first()

        if not gateway_api:
            # TODO
            raise Exception('not gateway api')
        fund_api = cls._create_payment_api(gateway_api, 'fundin')

        channel_config = cls._get_fund_channel_config(fund_channel)
        order_no = cls._generate_gateway_order_no(fund_channel)
        gateway_order_result.order_no = order_no
        response = fund_api(trade_code=order_no,
                            amount=amount, title=kwargs.pop('body', order_no), config=channel_config,
                            links=cls._make_links(gateway_order_result)
                            )

        gateway_order_result.order_no = response.get('trade_code', order_no)
        gateway_order_result.fee = response.get('fee', None)
        gateway_order_result.amount = amount
        gateway_order_result.real_amount = response.get('amount', None)
        gateway_order_result.result_code = response.get('result_code', None)
        gateway_order_result.result_message = response.get('result_message', None)
        extension = response.get('extension', None)
        if extension:
            if isinstance(extension, (dict)):
                import json
                gateway_order_result.extension = json.dumps(extension)
            else:
                gateway_order_result.extension = extension
        success = response.get('success', None)
        if not success:
            # 没有回复成功与不成功？
            gateway_order_result.status = GatewayOrderResult.STATUS_UNKNOWN
        if isinstance(success, (bool)):
            gateway_order_result.status = GatewayOrderResult.STATUS_SUCCESS if success else GatewayOrderResult.STATUS_FAILED
        # gateway_order_result.order_no = response.get('order_no', None)
        # if response.fee:
        #     gateway_order_result.free = response.get('fee', None)
        # if response.amount:
        #     gateway_order_result.amount = response.get('amount', amount)
        gateway_order_result.result_code = response.get('result_code', '')
        gateway_order_result.result_message = response.get('result_message', None)

        # 后续处理
        if gateway_order_result.status == GatewayOrderResult.STATUS_SUCCESS:
            gateway_order.status = GatewayOrder.STATUS_SENT

            if 'credential' in response:
                import json
                credential = json.dumps(response['credential'])
                gateway_order_result.credential = credential
                gateway_order_result.status = GatewayOrderResult.STATUS_WAIT_CREDENTIAL
                # trade_order.status = GatewayOrderResult.STATUS_WAIT_CREDENTIAL
                # trade_order.credential = credential
                # trade_order.status = TradeOrder.STATUS_WAIT_CREDENTIAL

                # for order in payment_orders:
                #     order.status = TradeOrder.STATUS_WAIT_CREDENTIAL

            else:
                gateway_order.status = GatewayOrder.STATUS_SENT

                for order in payment_orders:
                    order.status = TradeOrder.STATUS_SUCCESS
                    # trade_order.status = TradeOrder.STATUS_SUCCESS

        else:
            gateway_order.status = GatewayOrder.STATUS_FAILED
            for order in payment_orders:
                order.status = TradeOrder.STATUS_FAILED
        db.session.commit()

        return_url = kwargs.get('return_url', None)
        if return_url:
            cls.store_payment_result_return_url(gateway_order_result.id, return_url)
        # db.session.save(gateway_order)
        # db.session.save(gateway_order_result)
        return gateway_order_result

    @classmethod
    def create_fundin_trade(cls,
                            fund_channel,
                            amount,
                            currency,
                            trade_code,
                            *args, **kwargs):
        now = datetime.datetime.now()
        trade_order = TradeOrder(
            id='fundid{}'.format(time.time()),
            amount=amount,
            type='fundin',
            fund_channel_id=fund_channel.id,
            gateway_id=fund_channel.gateway.id,
            currency=currency,
            trade_code=trade_code,
            notify_status='none',
            notify_info=kwargs.pop('notify_info', None),
            created_at=now,
            updated_at=now,
            description=kwargs.pop('description', None)
        )
        db.session.add(trade_order)
        db.session.commit()
        return trade_order

        # trade_order.gateway_order = gateway_order
        # if True:
        #     # TODO, 未来可以根据网关的属性，是单笔还是批次发送,现在全是单笔
        #     gateway_order.next_submit_time = now
        #
        #     gateway_order_result = GatewayOrderResult(
        #         order_no=cls._create_gateway_result_order_no()
        #     )
        #     db.session.add(gateway_order_result)
        # db.session.add(trade_order)
        # db.session.add(gateway_order)
        # db.session.commit()
        # # 开始实际支付流程
        # gateway = fund_channel.gateway
        #
        # gateway_api = GatewayApi.query.filter(GatewayApi.gateway_id == gateway.id).filter(
        #     GatewayApi.type == 'fundin').first()
        #
        # if not gateway_api:
        #     # TODO
        #     raise Exception('not gateway api')
        # fund_api = cls._create_payment_api(gateway_api, 'fundin')
        #
        # # 查询资金源的配置
        # fund_channel_config = FundChannelConfig.query.filter(FundChannelConfig.fund_channel_id == fund_channel.id).all()
        #
        # channel_config = {}
        #
        # for config in fund_channel_config:
        #     channel_config[config.name] = config.name
        #     value_mode = config.value_mode
        #     if not value_mode or value_mode == 'string':
        #         value_separator = config.value_separator
        #         if value_separator:
        #             channel_config[config.name] = config.value.split(value_separator)
        #     else:
        #         channel_config[config.name] = config.value
        # response = fund_api(channel_config)
        #
        # gateway_order_result.order_no = response.get('trade_code', None)
        # gateway_order_result.fee = response.get('fee', None)
        # gateway_order_result.amount = response.get('amount', None)
        # gateway_order_result.result_code = response.get('result_code', None)
        # gateway_order_result.result_message = response.get('result_message', None)
        # extension = response.get('extension', None)
        # if extension:
        #     if isinstance(extension, (dict)):
        #         import json
        #         gateway_order_result.extension = json.dumps(extension)
        #     else:
        #         gateway_order_result.extension = extension
        # success = response.get('success', None)
        # if not success:
        #     # 没有回复成功与不成功？
        #     gateway_order_result.status = GatewayOrderResult.STATUS_UNKNOWN
        # if isinstance(success, (bool)):
        #     gateway_order_result.status = GatewayOrderResult.STATUS_SUCCESS if success else GatewayOrderResult.STATUS_FAILED
        # if response.trade_code:
        #     gateway_order_result.order_no = response.get('order_no', None)
        # if response.fee:
        #     gateway_order_result.free = response.get('fee', None)
        # if response.amount:
        #     gateway_order_result.amount = response.get('amount', amount)
        # gateway_order_result.result_code = response.get('result_code', None)
        # gateway_order_result.result_message = response.get('result_message', None)
        #
        # # 后续处理
        # if gateway_order_result.status == GatewayOrderResult.STATUS_SUCCESS:
        #     GatewayOrder.status = GatewayOrder.STATUS_SENT
        #
        #     if response.credential:
        #         import json
        #         credential = json.dumps(response.credential)
        #         gateway_order_result.credential = credential
        #         trade_order.status = GatewayOrderResult.STATUS_WAIT_CREDENTIAL
        #         trade_order.credential = credential
        #         trade_order.status = TradeOrder.STATUS_WAIT_CREDENTIAL
        #     else:
        #         gateway_order.status = GatewayOrder.STATUS_SENT
        #         trade_order.status = TradeOrder.STATUS_SUCCESS
        #
        # else:
        #     gateway_order.status = GatewayOrder.STATUS_FAILED
        #     trade_order.status = TradeOrder.STATUS_FAILED
        # db.session.save(trade_order)
        # db.session.save(gateway_order)
        # db.session.save(gateway_order_result)
        # return trade_order

    @classmethod
    def _create_payment_api(cls, gateway_api, default_func=None):
        if gateway_api.mode == 'local':
            api_address = gateway_api.api_address.split(':')
            import importlib
            module = importlib.import_module(api_address[0])
            func_name = default_func if not len(api_address) == 2 else api_address[1]

            if hasattr(module, func_name):
                return getattr(module, func_name)
            else:
                raise Exception('not func')
